參加 iTHome 鐵人賽最怕的是什麼?除了沒靈感、或是寫不完,甚至到最後忘記在午夜前按下「送出」按鈕,導致前功盡棄 QQ
今天,就讓我們一起動手,用自動化工具 n8n 打造一個忠實的發文提醒小助理。它會在每天晚上檢查你是否已發文,如果還沒,就立刻發送 Discord 通知,確保你不會因為一時疏忽而斷賽
這個流程的邏輯是: 「每天在指定時間觸發 -> 抓取你的鐵人賽 RSS -> 檢查最新一篇文章的發布日期 -> 如果最新文章不是今天發的 -> 就發送通知提醒自己」
這樣可以確保在午夜 12 點前,如果還沒發文,就會收到警告,避免斷賽的悲劇發生
在開始動手前,我們先用一張流程圖來理解整個自動化腳本的樣貌
graph TD
    A[開始] --> B[1. Schedule 排程觸發];
    B --> C[2. RSS Feed Read 讀取 RSS];
    C --> D[3. Aggregate 合併資料];
    D --> E{4. IF 判斷是否已發文};
    E -- 否/False --> F[5a. Discord 發送提醒];
    E -- 是/True --> G[5b. NoOp 結束流程];
來到儀表板,新增一個流程「Create Workflow」

初始節點選擇排程「On a schedule」

時間設定為晚上的 9pm

接著到設定的地方

設定為台灣時區

下個節點選擇「RSS Read」

URL 填入你鐵人賽的 RSS 網址

接著切換到「Settings」的分頁,把「Always Output Data」打開,避免第一天沒有資料就不會進行下去

為了方便後續的判斷,我們需要將 RSS 抓回來的多篇文章資料合併成一個陣列
下個節點選擇「Aggregate」來合併資料

選擇「All Item Data」會把列表的資料都放進「data」的變數裡面

下個節點選擇「IF」,用來判斷「最新文章的日期」是否等於「今天的日期」

判斷式內容填以下的內容,格式選擇「Boolean」的「is true」
{
  {
    $json.data.some(
      (item) =>
        new Date(item.isoDate).toISOString().split("T")[0] ===
        $now.toFormat("yyyy-MM-dd")
    );
  }
}

當 IF 節點判斷為 false 時,就傳送 Discord 通知,這邊的下個節點可以選擇「Discord」的「Send a message」來傳送訊息

「Connection Type」選擇「Webhook」,憑證的串接在之前的文章有撰寫過,這邊就不重複惹

Message 可以設定為
**🚨 iTHome 鐵人賽警告 🚨**
@everyone 今天還沒有發文喔!再不寫就要斷賽啦!
而當 IF 節點判斷為 true 時,我們什麼事都不用做,可以連接一個 NoOp (No Operation) 節點,讓流程圖看起來更完整、語意更清晰

可以點選最下方的「Execute workflow」來試跑看看,而完整的流程會長這樣,這邊也要記得到上方把流程切換為「Active」啟用

Discord 會收到這樣的訊息

最後也附上完整的流程 JSON 內容
{
  "nodes": [
    {
      "parameters": {
        "rule": {
          "interval": [
            {
              "triggerAtHour": 21
            }
          ]
        }
      },
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.2,
      "position": [0, 0],
      "id": "4e275616-c21c-411e-b510-bc2510aef7ca",
      "name": "Schedule Trigger"
    },
    {
      "parameters": {
        "url": "https://ithelp.ithome.com.tw/rss/series/8496",
        "options": {}
      },
      "type": "n8n-nodes-base.rssFeedRead",
      "typeVersion": 1.1,
      "position": [220, 0],
      "id": "9f72e3cb-8f20-4e5f-8732-79667a2cecbd",
      "name": "RSS Read",
      "alwaysOutputData": true
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 2
          },
          "conditions": [
            {
              "id": "b59baac4-6a94-434d-a9cb-ccbe13ab557b",
              "leftValue": "={{ $json.data.some(item => new Date(item.isoDate).toISOString().split('T')[0] === $now.toFormat('yyyy-MM-dd')) }}",
              "rightValue": "={{ $now.toFormat('yyyy-MM-dd') }}",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [660, 0],
      "id": "fdf179a3-e78f-4d53-9cb4-069871445fed",
      "name": "If"
    },
    {
      "parameters": {
        "authentication": "webhook",
        "content": "**🚨 iTHome 鐵人賽警告 🚨**\n@everyone \n<@YOUR_DISCORD_USER_ID>\n今天還沒有發文喔!再不寫就要斷賽啦!",
        "options": {}
      },
      "type": "n8n-nodes-base.discord",
      "typeVersion": 2,
      "position": [880, 100],
      "id": "80fdff87-081c-4fe4-8f23-c7387985eb54",
      "name": "Discord",
      "webhookId": "<REDACTED_WEBHOOK_ID>",
      "credentials": {}
    },
    {
      "parameters": {},
      "type": "n8n-nodes-base.noOp",
      "typeVersion": 1,
      "position": [880, -100],
      "id": "2e8a21ad-34db-4bd8-8391-3685b3f0e054",
      "name": "No Operation, do nothing"
    },
    {
      "parameters": {
        "aggregate": "aggregateAllItemData",
        "options": {}
      },
      "type": "n8n-nodes-base.aggregate",
      "typeVersion": 1,
      "position": [440, 0],
      "id": "2e31e8b0-7b45-463d-b117-7f5f4934a48c",
      "name": "Aggregate"
    }
  ],
  "connections": {
    "Schedule Trigger": {
      "main": [
        [
          {
            "node": "RSS Read",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "RSS Read": {
      "main": [
        [
          {
            "node": "Aggregate",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "If": {
      "main": [
        [
          {
            "node": "No Operation, do nothing",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Discord",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Aggregate": {
      "main": [
        [
          {
            "node": "If",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "pinData": {},
  "meta": {
    "templateCredsSetupCompleted": true,
    "instanceId": "<REDACTED_INSTANCE_ID>"
  }
}
這樣就完成了一個可靠的鐵人賽發文通知小助理,再也不用擔心忘記發文而斷賽惹。也祝大家順利完賽!